{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 原始代码实现 smote\n",
    "'''\n",
    "Created on 27/03/2017\n",
    "@author: Kaushal Shetty\n",
    "This is an implementation of the SMOTE Algorithm. \n",
    "See: \"SMOTE: synthetic minority over-sampling technique\" by\n",
    "Chawla, N.V et al.\n",
    "'''\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "import numpy as np\n",
    "import random\n",
    "from sklearn.neighbors import NearestNeighbors\n",
    "import math\n",
    "from random import randint\n",
    "import matplotlib.pyplot as plt\n",
    "from sklearn.decomposition import PCA\n",
    "\n",
    "\n",
    "class Smote(object):\n",
    "\t\"\"\"docstring for Smote\"\"\"\n",
    "\n",
    "\tdef __init__(self,distance):\n",
    "\t\tsuper(Smote, self).__init__()\n",
    "\t\tself.synthetic_arr=  []\n",
    "\t\tself.newindex = 0\n",
    "\t\tself.distance_measure = distance\n",
    "\n",
    "\n",
    "\n",
    "\tdef Populate(self,N,i,indices,min_samples,k):\n",
    "\t\t\"\"\"\n",
    "    \t\tPopulates the synthitic array\n",
    "    \t\tReturns:Synthetic Array to generate_syntheic_points \n",
    "    \t\"\"\"\n",
    "\n",
    "\t\twhile N!=0:\n",
    "\t\t\tarr = []\n",
    "\t\t\tnn = randint(0,k-2)\n",
    "\t\t\tfeatures = len(min_samples[0])\n",
    "\t\t\t\n",
    "\t\t\tfor attr in range(features):\n",
    "\t\t\t\tdiff = min_samples[indices[nn]][attr] - min_samples[i][attr]\n",
    "\t\t\t\tgap = random.uniform(0,1)\n",
    "\t\t\t\tarr.append(min_samples[i][attr] + gap*diff)\n",
    "\t\t\t\n",
    "\t\t\tself.synthetic_arr.append(arr)\n",
    "\t\t\tself.newindex = self.newindex + 1\n",
    "\t\t\tN = N-1\n",
    "\n",
    "\n",
    "\n",
    "\tdef k_neighbors(self,euclid_distance,k):\n",
    "\t\tnearest_idx_npy = np.empty([euclid_distance.shape[0],euclid_distance.shape[0]],dtype=np.int64)\n",
    "\t\t\n",
    "\t\tfor i in range(len(euclid_distance)):\n",
    "\t\t\tidx = np.argsort(euclid_distance[i])\n",
    "\t\t\tnearest_idx_npy[i] = idx\n",
    "\t\t\tidx = 0\n",
    "\n",
    "\t\treturn nearest_idx_npy[:,1:k]\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\tdef find_k(self,X,k):\n",
    "\n",
    "\t\t\"\"\"\n",
    "   \t\t\tFinds k nearest neighbors using euclidian distance\n",
    "   \t\t\tReturns: The k nearest neighbor   \n",
    "    \t\"\"\"\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "\t\teuclid_distance = np.empty([X.shape[0],X.shape[0]],dtype = np.float32)\n",
    "\t\t\n",
    "\t\tfor i in range(len(X)):\n",
    "\t\t\tdist_arr = []\n",
    "\t\t\tfor j in range(len(X)):\n",
    "\t\t\t\tdist_arr.append(math.sqrt(sum((X[j]-X[i])**2)))\n",
    "\t\t\tdist_arr = np.asarray(dist_arr,dtype = np.float32)\n",
    "\t\t\teuclid_distance[i] = dist_arr\n",
    "\n",
    "\t\treturn self.k_neighbors(euclid_distance,k)\n",
    "\n",
    "\n",
    "\tdef generate_synthetic_points(self,min_samples,N,k):\n",
    "\n",
    "\t\t\"\"\"\n",
    "    \t\tReturns (N/100) * n_minority_samples synthetic minority samples.\n",
    "    \t\tParameters\n",
    "    \t\t----------\n",
    "    \t\tmin_samples : Numpy_array-like, shape = [n_minority_samples, n_features]\n",
    "    \t\t    Holds the minority samples\n",
    "    \t\tN : percetange of new synthetic samples: \n",
    "    \t\t    n_synthetic_samples = N/100 * n_minority_samples. Can be < 100.\n",
    "    \t\tk : int. Number of nearest neighbours. \n",
    "    \t\tReturns\n",
    "    \t\t-------\n",
    "    \t\tS : Synthetic samples. array, \n",
    "    \t\t    shape = [(N/100) * n_minority_samples, n_features]. \n",
    "    \t\"\"\"\n",
    "\t\t\n",
    "\n",
    "\t\tif N < 100:\n",
    "\t\t\traise ValueError(\"Value of N cannot be less than 100%\")\n",
    "\n",
    "\t\tif self.distance_measure not in ('euclidian','ball_tree'):\n",
    "\t\t\traise ValueError(\"Invalid Distance Measure.You can use only Euclidian or ball_tree\")\n",
    "\n",
    "\n",
    "\t\tif k>min_samples.shape[0]:\n",
    "\t\t\traise ValueError(\"Size of k cannot exceed the number of samples.\")\n",
    "\n",
    "\t\t\n",
    "\t\tN = int(N/100)\n",
    "\t\tT = min_samples.shape[0]\n",
    "\t\t\n",
    "\t\t\n",
    "\n",
    "\t\tif self.distance_measure == 'euclidian':\n",
    "\t\t\t\tindices = self.find_k(min_samples,k)\n",
    "\t\t\t\n",
    "\t\telif self.distance_measure=='ball_tree':\n",
    "\t\t\tnb = NearestNeighbors(n_neighbors = k,algorithm= 'ball_tree').fit(min_samples)\n",
    "\t\t\tdistance,indices = nb.kneighbors(min_samples)\n",
    "\t\t\tindices = indices[:,1:]\t\n",
    "\n",
    "\n",
    "\n",
    "\t\tfor i in range(indices.shape[0]):\n",
    "\t\t\tself.Populate(N,i,indices[i],min_samples,k)\n",
    "\t\t\n",
    "\t\treturn np.asarray(self.synthetic_arr)\n",
    "\n",
    "\t\t\n",
    "\n",
    "\n",
    "\tdef plot_synthetic_points(self,min_samples,N,k):\n",
    "\t\t\"\"\"\n",
    "\t\t\tPlot the over sampled synthtic samples in a scatterplot\n",
    "\t\t\"\"\"\n",
    "\n",
    "\n",
    "\t\tif N < 100:\n",
    "\t\t\traise ValueError(\"Value of N cannot be less than 100%\")\n",
    "\n",
    "\t\tif self.distance_measure not in ('euclidian','ball_tree'):\n",
    "\t\t\traise ValueError(\"Invalid Distance Measure.You can use only Euclidian or ball_tree\")\n",
    "\n",
    "\n",
    "\t\tif k>min_samples.shape[0]:\n",
    "\t\t\traise ValueError(\"Size of k cannot exceed the number of samples.\")\n",
    "\n",
    "\t\t\n",
    "\t\tsynthetic_points = self.generate_synthetic_points(min_samples,N,k)\n",
    "\t\t\n",
    "\t\tpca = PCA(n_components=2)\n",
    "\t\tpca.fit(synthetic_points)\n",
    "\t\tpca_synthetic_points = pca.transform(synthetic_points)\n",
    "\t\t\n",
    "\t\tplt.scatter(pca_synthetic_points[:,0],pca_synthetic_points[:,1])\n",
    "\t\tplt.show()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.9"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
